package rivta.labs.schematronvalidation

import org.junit.Before
import org.junit.Test

import javax.xml.transform.Source
import javax.xml.transform.TransformerException
import javax.xml.transform.TransformerFactory
import javax.xml.transform.URIResolver
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource

import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertNotNull

class ExternalConstraintsTest {

    def transformerFactory

    @Before
    void setup() {
        transformerFactory = TransformerFactory.newInstance()

        transformerFactory.setURIResolver(new URIResolver() {
            @Override
            Source resolve(String href, String base) throws TransformerException {
                source("/xslt/" + href)
            }
        })
    }

    @Test
    void testRequest() {

        def gatheredConstraints = gatherContraints(source("/xml/constraints.xml"))

        def expandedConstraints = expandContraints(stringSource(gatheredConstraints))

        def rules = convertToRules(stringSource(expandedConstraints))

        def validationResults = validateDocument(source("/xml/GetCareContacts.xml"), stringSource(rules))

        def resultDoc = new XmlSlurper().parseText(validationResults)

        def failedAsserts = resultDoc.breadthFirst().findAll { child -> child.name() == "failed-assert" }

        assertEquals("Should have one failure", 1, failedAsserts.size())
    }

    @Test
    void testResponse() {

        def gatheredConstraints = gatherContraints(source("/xml/constraints.xml"))

        def expandedConstraints = expandContraints(stringSource(gatheredConstraints))

        def rules = convertToRules(stringSource(expandedConstraints))

        def validationResults = validateDocument(source("/xml/GetCareContactsResponse.xml"), stringSource(rules))

        def resultDoc = new XmlSlurper().parseText(validationResults)

        def failedAsserts = resultDoc.breadthFirst().findAll { child -> child.name() == "failed-assert" }

        failedAsserts.each {println it.text()}

        assertEquals("Should have one failure", 1, failedAsserts.size())
    }

    private String gatherContraints(Source constraints) {
        transform(source("/xslt/iso_dsdl_include.xsl"), constraints)
    }

    private String expandContraints(Source gatheredConstraints) {
        transform(source("/xslt/iso_abstract_expand.xsl"), gatheredConstraints)
    }

    private String convertToRules(Source expandedConstraints) {
        transform(source("/xslt/iso_svrl_for_xslt2.xsl"), expandedConstraints)
    }

    private String validateDocument(Source document, Source rules) {
        transform(rules, document)
    }

    String transform(Source templateSource, Source documentSource) {
        def transformer = transformerFactory.newTransformer(templateSource)
        def result = new StringResult()
        transformer.transform(documentSource, result)

        result.toString()
    }

    Source source(path) {
        def resource = this.getClass().getResourceAsStream(path)
        assertNotNull("resource is null", resource)
        new StreamSource(resource)
    }

    Source stringSource(contents) {
        new StreamSource(new StringReader(contents))
    }

    class StringResult extends StreamResult {
        StringWriter writer

        StringResult() {
            super()
            writer = new StringWriter()
            setWriter(writer)
        }

        @Override
        String toString() {
            writer.toString()
        }
    }
}
